<!DOCTYPE html>
<html>
<head>
	<title>CIS</title>
	<meta charset="UTF-8">
	<style type="text/css">
			*{
				margin:0;
				padding:0;
			}
			body{
				width:100%;
				height:100%;
				background:url(images/bgi.jpg) no-repeat  0px 0px;
				background-size:cover;
				background-attachment: fixed;
			}
	</style>
	<script src="js/echarts.js"></script>
	<script src="js/jquery.min.js"></script>
</head>

<body>
	<div id="main" style="width:50%;height:50%;position:absolute"></div>
	
	<script type="text/javascript">

	//json中的两个属性resources和orders分别使用demensions.oeders.data一级demensions.resources.data获取,定义维度坐标时
	//采用rowdata.resources.demensions获取坐标维度信息
	    var HEIGHT_RATIO = 0.6;//显示的元素的高度倍数
		var DIM_CATEGORY_INDEX = 0;//对应的纵坐标
		var DIM_ORDER_START = 1;//开始时间，对应横坐标的开始
		var DIM_ORDER_END = 2;//结束时间，对应横坐标的结束
		var DATA_ZOOM_AUTO_MOVE_THROTTLE = 30;
		var DATA_ZOOM_X_INSIDE_INDEX = 1;
		var DATA_ZOOM_Y_INSIDE_INDEX = 3;
		var DATA_ZOOM_AUTO_MOVE_SPEED = 0.2;
		var DATA_ZOOM_AUTO_MOVE_DETECT_AREA_WIDTH = 30;

		var _draggable;
		var _draggingEl;
		var _dropShadow;
		var _draggingCursorOffset = [0, 0];
		var _draggingTimeLength;
		var _draggingRecord;
		var _dropRecord;
		var _cartesianXBounds = [];
		var _cartesianYBounds = [];
		var _rawData;
		var _autoDataZoomAnimator;	
		var dataArr = [];
		var count = 0;
		var colorList = ['#003f65','#0977bb','#4daeeb','#82c8f3','#add9f5','#c2e0f3','#e6ecf0','#7b9ce1','#bd6d6c','#75d874','#e0bc78','#dc77dc','#72b362'];//颜色数组
		
		var myChart = echarts.init(document.getElementById('main'));
		
		$.get('json/test.json', function (rawData) {
		    _rawData = rawData;
		    myChart.setOption(option = makeOption());
		    initDrag();
		},"json");
		
		function makeOption() {
		    return {
		        tooltip: {
		        },
		        animation: false,
		        toolbox: {
		            left: 20,
		            top: 0,
		            itemSize: 20,
		            feature: {
		                myDrag: {
		                    show: true,
		                    title: 'Make bars\ndraggable',
		                    icon: 'path://M990.55 380.08 q11.69 0 19.88 8.19 q7.02 7.01 7.02 18.71 l0 480.65 q-1.17 43.27 -29.83 71.93 q-28.65 28.65 -71.92 29.82 l-813.96 0 q-43.27 -1.17 -72.5 -30.41 q-28.07 -28.07 -29.24 -71.34 l0 -785.89 q1.17 -43.27 29.24 -72.5 q29.23 -29.24 72.5 -29.24 l522.76 0 q11.7 0 18.71 7.02 q8.19 8.18 8.19 18.71 q0 11.69 -7.6 19.29 q-7.6 7.61 -19.3 7.61 l-518.08 0 q-22.22 1.17 -37.42 16.37 q-15.2 15.2 -15.2 37.42 l0 775.37 q0 23.39 15.2 38.59 q15.2 15.2 37.42 15.2 l804.6 0 q22.22 0 37.43 -15.2 q15.2 -15.2 16.37 -38.59 l0 -474.81 q0 -11.7 7.02 -18.71 q8.18 -8.19 18.71 -8.19 l0 0 ZM493.52 723.91 l-170.74 -170.75 l509.89 -509.89 q23.39 -23.39 56.13 -21.05 q32.75 1.17 59.65 26.9 l47.94 47.95 q25.73 26.89 27.49 59.64 q1.75 32.75 -21.64 57.3 l-508.72 509.9 l0 0 ZM870.09 80.69 l-56.13 56.14 l94.72 95.9 l56.14 -57.31 q8.19 -9.35 8.19 -21.05 q-1.17 -12.86 -10.53 -22.22 l-47.95 -49.12 q-10.52 -9.35 -23.39 -9.35 q-11.69 -1.17 -21.05 7.01 l0 0 ZM867.75 272.49 l-93.56 -95.9 l-380.08 380.08 l94.73 94.73 l378.91 -378.91 l0 0 ZM322.78 553.16 l38.59 39.77 l-33.92 125.13 l125.14 -33.92 l38.59 38.6 l-191.79 52.62 q-5.85 1.17 -12.28 0 q-6.44 -1.17 -11.11 -5.84 q-4.68 -4.68 -5.85 -11.7 q-2.34 -5.85 0 -11.69 l52.63 -192.97 l0 0 Z',
		                    onclick: onDragSwitchClick
		                }
		            }
		        },
		        title: {
		            text: 'CISDI 资源甘特图',
		            left: 'center'
		        },
		        dataZoom: [{
		            type: 'slider',
		            xAxisIndex: 0,
		            filterMode: 'empty',
		            height: 20,
		            bottom: 0,
		            start: 0,
		            end: 26,
		            handleIcon: 'M10.7,11.9H9.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4h1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z',
		            handleSize: '80%',
		            showDetail: false
		        }, {
		            type: 'inside',
		            id: 'insideX',
		            xAxisIndex: 0,
		            filterMode: 'empty',
		            start: 0,
		            end: 26,
		            throttle:100,
		            zoomOnMouseWheel: true,
		            moveOnMouseMove: true
		        }, {
		            type: 'slider',
		            yAxisIndex: 0,
		            filterMode: 'empty',
		            width:10,
		            bottom: 20,
		            start: 0,
		            end: 18,
		            handleIcon: 'M10.7,11.9H9.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4h1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z',
		            handleSize: '50%',
		            showDetail: false
		        }, {
		            type: 'inside',
		            id: 'insideY',
		            yAxisIndex: 0,
		            filterMode: 'empty',
		            start: 0,
		            end: 50,
		            zoomOnMouseWheel: true,
		            moveOnMouseMove: true
		        }],
		        grid: {
		            show: true,
		            top: 70,
		            bottom: 20,
		            left: 100,
		            right: 20,
		            borderWidth: 0
		        },
		        xAxis: {//定义X轴，类型为时间
		            type: 'time',
		            position: 'top',
		            splitLine: {
		                lineStyle: {
		                    color: ['#E9EDFF']
		                }
		            },
		            axisLine: {
		                show: false
		            },
		            axisTick: {
		                lineStyle: {
		                    color: '#929ABA'
		                }
		            },
		            axisLabel: {
		                color: '#929ABA',
		                inside: false,
		                align: 'center'
		            }
		        },
		        yAxis: {//定义Y轴
		        	inverse:true,
		            axisTick: {show: false},
		            splitLine: {show: false},
		            axisLine: {show: false},
		            axisLabel: {show: false},
		            min: 0.5,
		            max: _rawData.resources.data.length+0.5//长度最大为源文件中数据条数+1
		        },
		        series: [{
		            id: 'scheduleData',
		            type: 'custom',
		            renderItem: renderGanttItem,
		            dimensions: _rawData.orders.dimensions,
		            encode: {
		                x: [DIM_ORDER_START, DIM_ORDER_END],//x，y一起对应了一个位置，在这个格子中显示的数据
		                y: DIM_CATEGORY_INDEX,
		                tooltip: ["订单号", "开始时间", "结束时间", "当前资源", "下一资源"]
		            },
		            data: _rawData.orders.data//数据来源
		        }, {
		            type: 'custom',
		            renderItem: renderAxisLabelItem,
		            dimensions: _rawData.resources.dimensions,//用于定义维度，这里用resources定义y轴
		            encode: {
		                x: -1, // 表示不受x轴控制
		                y: 0//表示第0维映射到y轴
		            },
		            data: echarts.util.map(_rawData.resources.data, function (item, index) {
		                return item;
		            })
		        }]
		    };
		}
				
		//为不同的order渲染不同的颜色
		function renderColorItem(params,api){
			var count=colorList.length;					
			var orderID = api.value(3) % count;
			if(orderID){
				return colorList[orderID];
			}
		}
		
		function renderGanttItem(params, api) {//定义渲染数据项item
		    var categoryIndex = api.value(DIM_CATEGORY_INDEX);
		    //coord()函数将data映射为坐标系上的点，返回的是点的坐标数组，对于Cartesian坐标系来说，返回   [x轴值，y轴值，z轴值]
		    var timeStart = api.coord([api.value(DIM_ORDER_START), categoryIndex]);
		    var timeEnd = api.coord([api.value(DIM_ORDER_END), categoryIndex]);

		    var coordSys = params.coordSys;
		    _cartesianXBounds[0] = coordSys.x;
		    _cartesianXBounds[1] = coordSys.x + coordSys.width;
		    _cartesianYBounds[0] = coordSys.y;
		    _cartesianYBounds[1] = coordSys.y + coordSys.height;

		    var barLength = timeEnd[0] - timeStart[0];
		    // Get the heigth corresponds to length 1 on y axis.
		    var barHeight = api.size([0, 1])[1] * HEIGHT_RATIO;//得到一个高度，就是显示出来的块儿的高度
		    var x = timeStart[0];
		    var y = timeStart[1] - barHeight;
		    
		    var orderNumber = api.value(4);
		    // var  orderNumberWidth = echarts.format.getTextRect(orderNumber).width;
		    var text = orderNumber;
			// (barLength > orderNumberWidth + 40 && x + barLength >= 180)
		    //     ? orderNumber :(api.value(0));

		    var rectNormal = clipRectByRect(params, {
		        x: x, y: y, width: barLength, height: barHeight
		    });
		    
		    var rectColor = clipRectByRect(params, {
		        x: x, y: y, width: barLength, height: barHeight
		    });
		    
		    var rectText = clipRectByRect(params, {
		        x: x, y: y, width: barLength, height: barHeight
		    });
		    
		    //orderItem逻辑路径
		    // var polylineLink;
		    
		    // dataArr[dataArr.length] = [api.value(0),x+barLength,y+barHeight];//api.value()用于连线的基准维度，此处为订单号相同
		    count++;
		    if(dataArr.length>1&& api.value(0)==dataArr[count-2][0]){//同一个订单的连线逻辑
		    	polylineLink ={ points:[
		    		[dataArr[count-2][1],dataArr[count-2][2]],
		    		[dataArr[count-2][1],(dataArr[count-1][2]-dataArr[count-2][2]-barHeight)/2+dataArr[count-2][2]],
		    		[dataArr[count-1][1]-barLength,(dataArr[count-1][2]-dataArr[count-2][2]-barHeight)/2+dataArr[count-2][2]],
		    		[dataArr[count-1][1]-barLength,dataArr[count-1][2]-barHeight]
		    	],
		    	smooth:0.0
		    	};
		    	return {
			        type: 'group',
			        children: [{
			            type: 'rect',
			            ignore: !rectNormal,
			            shape: rectNormal,
			            style: api.style()
			        },{
			            type: 'rect',
			            ignore: !rectColor,
			            shape: rectColor,
			            style: api.style({fill:renderColorItem(params,api)})
			        },{
			            type: 'rect',
			            ignore: !rectText,
			            shape: rectText,
			            style: api.style({
			                fill: 'transparent',
			                stroke: 'transparent',
			                text: text,
			                textFill: '#fff'
			            })
			        },{
			            type: 'polyline',
			            ignore: !polylineLink,
			            shape: polylineLink,
			            style: api.style({lineWidth:2,stroke:renderColorItem(params,api),fill:''})
			        }]
		    	};
		    }else{
			    return {
			        type: 'group',
			        children: [{
			            type: 'rect',
			            ignore: !rectNormal,
			            shape: rectNormal,
			            style: api.style()
			        },{
			            type: 'rect',
			            ignore: !rectColor,
			            shape: rectColor,
			            style: api.style({fill:renderColorItem(params,api)})
			        },{
			            type: 'rect',
			            ignore: !rectText,
			            shape: rectText,
			            style: api.style({
			                fill: 'transparent',
			                stroke: 'transparent',
			                text: text,
			                textFill: '#fff'
			            })
			        }]
			    };
		    }		    		    
		}
       
		function renderAxisLabelItem(params, api) {//呈现现有标签（渲染标签）y轴的部分，左边纵坐标的渲染
		    var y = api.coord([0, api.value(0)])[1];
		    if (y < params.coordSys.y + 5) {
		        return;
		    }
		    return {
		        type: 'group',
		        position: [
		            10,
		            y
		        ],
		        children: [{
		            type: 'path',
		            shape: {
		                d: 'M0,0 L0,-20 L30,-20 C42,-20 38,-1 50,-1 L70,-1 L70,0 Z',
		                x: 0,
		                y: -20,
		                width: 90,
		                height: 20,
		                layout: 'cover'
		            },
		            style: {
		                fill: '#025780'
		            }
		        }, {
		            type: 'text',
		            style: {
		                x: 24,
		                y: -3,
		                text: api.value(1),
		                textVerticalAlign: 'bottom',
		                textAlign: 'center',
		                textFill: '#fff'
		            }
		        }, {
		            type: 'text',
		            style: {
		                x: 75,
		                y: -2,
		                textVerticalAlign: 'bottom',
		                textAlign: 'center',
		                text: api.value(2),
		                textFill: '#000'
		            }
		        }]
		    };
		}

		function clipRectByRect(params, rect) {//剪辑
		    return echarts.graphic.clipRectByRect(rect, {
		        x: params.coordSys.x,
		        y: params.coordSys.y,
		        width: params.coordSys.width,
		        height: params.coordSys.height
		    });
		}
		
		function onDragSwitchClick(model, api, type) {//拖动开关			
		    _draggable = !_draggable;
		    myChart.setOption({
		        dataZoom: [{
		            id: 'insideX',
		            disabled: _draggable
		        }, {
		            id: 'insideY',
		            disabled: _draggable
		        }]
		    });
		    this.model.setIconStatus(type, _draggable ? 'emphasis' : 'normal');
		}
		
		function initDrag() {//初始化拖动

		    _autoDataZoomAnimator = makeAnimator(dispatchDataZoom);

		    myChart.on('mousedown', function (param) {
		        if (!_draggable || !param || param.seriesIndex == null) {
		            return;
		        }

		        // Drag start
		        _draggingRecord = {
		            dataIndex: param.dataIndex,
		            categoryIndex: param.value[DIM_CATEGORY_INDEX],
		            timeStart: param.value[DIM_ORDER_START],
		            timeEnd: param.value[DIM_ORDER_END]
		        };
		        var style = {lineWidth: 2, fill: 'rgba(255,0,0,0.1)', stroke: 'rgba(255,0,0,0.8)', lineDash: [6, 3]};

		        _draggingEl = addOrUpdateBar(_draggingEl, _draggingRecord, style, 100);
		        _draggingCursorOffset = [
		            _draggingEl.position[0] - param.event.offsetX,
		            _draggingEl.position[1] - param.event.offsetY
		        ];
		        _draggingTimeLength = _draggingRecord.timeEnd - _draggingRecord.timeStart;
		    });

		    myChart.getZr().on('mousemove', function (event) {//为元素绑定鼠标悬浮事件（移动鼠标）
		        if (!_draggingEl) {
		            return;
		        }

		        var cursorX = event.offsetX;
		        var cursorY = event.offsetY;

		        // Move _draggingEl.
		        _draggingEl.attr('position', [
		            _draggingCursorOffset[0] + cursorX,
		            _draggingCursorOffset[1] + cursorY,
		        ]);

		        prepareDrop();

		        autoDataZoomWhenDraggingOutside(cursorX, cursorY);
		    });

		    myChart.getZr().on('mouseup', function () {//松开鼠标
		        // Drop
		        if (_draggingEl && _dropRecord) {

		            updateRawData() && myChart.setOption({
		                series: {
		                    id: 'scheduleData',
		                    data: _rawData.orders.data
		                }
		            });
		        }
		        dragRelease();
		    });
		    myChart.getZr().on('globalout', dragRelease);//myChart.getZr().on()就是图表监听事件

		    function dragRelease() {
		        _autoDataZoomAnimator.stop();

		        if (_draggingEl) {
		            myChart.getZr().remove(_draggingEl);
		            _draggingEl = null;
		        }
		        if (_dropShadow) {
		            myChart.getZr().remove(_dropShadow);
		            _dropShadow = null;
		        }
		        _dropRecord = _draggingRecord = null;
		    }

		    function addOrUpdateBar(el, itemData, style, z) {//添加或更新盒子
		        var orderStart = myChart.convertToPixel('grid', [itemData.timeStart, itemData.categoryIndex]);//此函数用于可视化
		        var orderEnd = myChart.convertToPixel('grid', [itemData.timeEnd, itemData.categoryIndex]);

		        var barLength = orderEnd[0] - orderStart[0];
		        var barHeight = Math.abs(
		            myChart.convertToPixel('grid', [0, 0])[1] - myChart.convertToPixel('grid', [0, 1])[1]
		        ) * HEIGHT_RATIO;

		        if (!el) {
		            el = new echarts.graphic.Rect({
		                shape: {x: 0, y: 0, width: 0, height: 0},
		                style: style,
		                z: z
		            });
		            myChart.getZr().add(el);
		        }
		        el.attr({
		            shape: {x: 0, y: 0, width: barLength, height: barHeight},
		            position: [orderStart[0], orderStart[1] - barHeight]
		        });
		        return el;
		    }

		    function prepareDrop() {
		        // Check droppable place.
		        var xPixel = _draggingEl.shape.x + _draggingEl.position[0];
		        var yPixel = _draggingEl.shape.y + _draggingEl.position[1];
		        var cursorData = myChart.convertFromPixel('grid', [xPixel, yPixel]);
		        if (cursorData) {
		            // Make drop shadow and _dropRecord
		            _dropRecord = {
		                categoryIndex: Math.floor(cursorData[1]),
		                orderStart: cursorData[0],
		                orderEnd: cursorData[0] + _draggingTimeLength
		            };
		            var style = {fill: 'rgba(0,0,0,0.4)'};
		            _dropShadow = addOrUpdateBar(_dropShadow, _dropRecord, style, 99);
		        }
		    }

		    // 
		    function updateRawData() {
		        var orderData = _rawData.orders.data;
		        var movingItem = orderData[_draggingRecord.dataIndex];

		        // Check conflict
		        for (var i = 0; i < orderData.length; i++) {
		            var dataItem = orderData[i];
		            if (dataItem !== movingItem
		                && _dropRecord.categoryIndex === dataItem[DIM_CATEGORY_INDEX]
		                && _dropRecord.orderStart < dataItem[DIM_ORDER_END]
		                && _dropRecord.orderEnd > dataItem[DIM_ORDER_START]
		            ) {
		                alert('时间冲突! 请合理选择!');
		                return;
		            }
		        }

		        // No conflict.
		        movingItem[DIM_CATEGORY_INDEX] = _dropRecord.categoryIndex;
		        movingItem[DIM_ORDER_START] = _dropRecord.orderStart;
		        movingItem[DIM_ORDER_END] = _dropRecord.orderEnd;
		        return true;
		    }

		    function autoDataZoomWhenDraggingOutside(cursorX, cursorY) {
		        // When cursor is outside the cartesian and being dragging,
		        // auto move the dataZooms.
		        var cursorDistX = getCursorCartesianDist(cursorX, _cartesianXBounds);
		        var cursorDistY = getCursorCartesianDist(cursorY, _cartesianYBounds);

		        if (cursorDistX !== 0 || cursorDistY !== 0) {
		            _autoDataZoomAnimator.start({
		                cursorDistX: cursorDistX,
		                cursorDistY: cursorDistY
		            });
		        }
		        else {
		            _autoDataZoomAnimator.stop();
		        }
		    }

		    function dispatchDataZoom(params) {
		        var option = myChart.getOption();
		        var optionInsideX = option.dataZoom[DATA_ZOOM_X_INSIDE_INDEX];
		        var optionInsideY = option.dataZoom[DATA_ZOOM_Y_INSIDE_INDEX];
		        var batch = [];

		        prepareBatch(batch, 'insideX', optionInsideX.start, optionInsideX.end, params.cursorDistX);
		        prepareBatch(batch, 'insideY', optionInsideY.start, optionInsideY.end, -params.cursorDistY);

		        batch.length && myChart.dispatchAction({
		            type: 'dataZoom',
		            batch: batch
		        });

		        function prepareBatch(batch, id, start, end, cursorDist) {
		            if (cursorDist === 0) {
		                return;
		            }
		            var sign = cursorDist / Math.abs(cursorDist);
		            var size = end - start;
		            var delta = DATA_ZOOM_AUTO_MOVE_SPEED * sign;

		            start += delta;
		            end += delta;

		            if (end > 100) {
		                end = 100;
		                start = end - size;
		            }
		            if (start < 0) {
		                start = 0;
		                end = start + size;
		            }
		            batch.push({
		                dataZoomId: id,
		                start: start,
		                end: end
		            });
		        }
		    }

		    function getCursorCartesianDist(cursorXY, bounds) {
		        var dist0 = cursorXY - (bounds[0] + DATA_ZOOM_AUTO_MOVE_DETECT_AREA_WIDTH);
		        var dist1 = cursorXY - (bounds[1] - DATA_ZOOM_AUTO_MOVE_DETECT_AREA_WIDTH);
		        return dist0 * dist1 <= 0
		            ? 0 // cursor is in cartesian
		            : dist0 < 0
		            ? dist0 // cursor is at left/top of cartesian
		            : dist1; // cursor is at right/bottom of cartesian
		    }

		    function makeAnimator(callback) {
		        var requestId;
		        var callbackParams;
		        // Use throttle to prevent from calling dispatchAction frequently.
		        callback = echarts.throttle(callback, DATA_ZOOM_AUTO_MOVE_THROTTLE);

		        function onFrame() {
		            callback(callbackParams);
		            requestId = requestAnimationFrame(onFrame);
		        }

		        return {
		            start: function (params) {
		                callbackParams = params;
		                if (requestId == null) {
		                    onFrame();
		                }
		            },
		            stop: function () {
		                if (requestId != null) {
		                    cancelAnimationFrame(requestId);
		                }
		                requestId = callbackParams = null;
		            }
		        };
		    }
		}

	</script>
	
</body>
</html>